/**
 * @file main.cpp
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2025-06-20
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#include "main.h"
#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

typedef struct __attribute__((packed))
{
    uint32_t frame_id;    
    uint8_t type;         
    uint16_t src_module;  
    uint16_t dst_module;  
    uint8_t fc;           
    uint8_t content_len;  
} msg_header_t;

//最大数据长度数据包
typedef struct __attribute__((packed))
{
  msg_header_t header;
  uint8_t content[256]; // 内容
}msg_packet_t;

// 函数声明
std::vector<std::string> findAvailableComPorts();
std::vector<std::string> findBinFiles(const std::string& directory);
bool selectComPort(std::string& selectedPort);
bool selectBinFile(std::string& selectedFile);
void clearInputBuffer();

std::string strFilePath = "../../config.json";

int main()
{
    // 解决打印汉字乱码
    system("chcp 65001");

    // 自动检测并选择串口
    std::string selectedPort;
    if (!selectComPort(selectedPort)) {
        BUGLOG("未选择串口，退出程序 ");
        return 0;
    }
    
    BUGLOG("选择的串口: %s ", selectedPort.c_str());

    // 自动查找并选择bin文件
    std::string selectedBinFile;
    if (!selectBinFile(selectedBinFile)) {
        BUGLOG("未选择固件文件，退出程序 ");
        return 0;
    }
    
    BUGLOG("选择的固件文件: %s ", selectedBinFile.c_str());

    // 打开指定串口并进行配置
    if (!ConnectCom(selectedPort.c_str())) {
        BUGLOG("串口连接失败，退出程序 ");
        return 0;
    }

    // 进行固件升级
    update_mcu(selectedBinFile.c_str(),strFilePath.c_str());

    // 等待用户按键退出
    BUGLOG("执行完成，按任意键退出... ");
    getchar();
    getchar(); // 需要两个getchar()因为第一个会读取之前选择菜单时留下的回车符

    return 0;
}

// 查找可用串口
std::vector<std::string> findAvailableComPorts() {
    std::vector<std::string> comPorts;
    
    // 在Windows上，尝试打开COM1到COM256来检测可用串口
    for (int i = 1; i <= 256; i++) {
        std::string portName = "\\\\.\\COM" + std::to_string(i);
        HANDLE hCom = CreateFileA(portName.c_str(), GENERIC_READ | GENERIC_WRITE, 
                                0, NULL, OPEN_EXISTING, 0, NULL);
        
        if (hCom != INVALID_HANDLE_VALUE) {
            // 获取串口信息以确认它是真实设备
            DCB dcb;
            if (GetCommState(hCom, &dcb)) {
                comPorts.push_back(portName);
            }
            CloseHandle(hCom);
        }
    }
    
    return comPorts;
}

// 查找指定目录下的bin文件
std::vector<std::string> findBinFiles(const std::string& directory) {
    std::vector<std::string> binFiles;
    
    // 使用Windows API查找文件
    WIN32_FIND_DATAA findFileData;
    HANDLE hFind;
    std::string searchPath = directory + "\\*.bin";
    
    hFind = FindFirstFileA(searchPath.c_str(), &findFileData);
    
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                std::string fullPath = directory + "\\" + std::string(findFileData.cFileName);
                // 将反斜杠转换为正斜杠以避免转义问题
                std::replace(fullPath.begin(), fullPath.end(), '\\', '/');
                binFiles.push_back(fullPath);
            }
        } while (FindNextFileA(hFind, &findFileData) != 0);
        
        FindClose(hFind);
    }
    
    return binFiles;
}

// 选择串口
bool selectComPort(std::string& selectedPort) {
    BUGLOG("正在检测可用串口... ");
    std::vector<std::string> comPorts = findAvailableComPorts();
    
    if (comPorts.empty()) {
        BUGLOG("未找到可用串口 ");
        return false;
    }
    
    BUGLOG("找到以下串口: ");
    for (size_t i = 0; i < comPorts.size(); i++) {
        // 显示更友好的串口名称（去掉"\\\\.\\"前缀）
        std::string displayName = comPorts[i].substr(4);
        BUGLOG("%zu: %s", i + 1, displayName.c_str());
    }
    
    // 如果有多个串口，让用户选择
    if (comPorts.size() > 1) {
        BUGLOG("请选择要使用的串口 (1-%zu): ", comPorts.size());
        int choice;
        if (scanf("%d", &choice) != 1) {
            BUGLOG("输入无效 ");
            clearInputBuffer();
            return false;
        }
        clearInputBuffer();
        
        if (choice < 1 || choice > static_cast<int>(comPorts.size())) {
            BUGLOG("无效选择 ");
            return false;
        }
        
        selectedPort = comPorts[choice - 1];
    } else {
        // 如果只有一个串口，直接使用
        selectedPort = comPorts[0];
        BUGLOG("自动选择串口: %s ", selectedPort.substr(4).c_str());
    }
    
    return true;
}

// 选择bin文件
bool selectBinFile(std::string& selectedFile) {
    // 在当前目录和上级目录查找bin文件
    std::vector<std::string> searchDirs = {".", "..", "../.."};
    std::vector<std::string> binFiles;
    
    for (const auto& dir : searchDirs) {
        BUGLOG("在目录 %s 中查找固件文件... ", dir.c_str());
        auto filesInDir = findBinFiles(dir);
        binFiles.insert(binFiles.end(), filesInDir.begin(), filesInDir.end());
    }
    
    if (binFiles.empty()) {
        BUGLOG("未找到任何.bin固件文件 ");
        return false;
    }
    
    BUGLOG("找到以下固件文件: ");
    for (size_t i = 0; i < binFiles.size(); i++) {
        // 提取文件名（去掉路径）
        size_t lastSlash = binFiles[i].find_last_of("/");
        std::string fileName = (lastSlash != std::string::npos) ? 
                              binFiles[i].substr(lastSlash + 1) : binFiles[i];
        BUGLOG("%zu: %s (%s) ", i + 1, fileName.c_str(), binFiles[i].c_str());
    }
    
    // 如果有多个文件，让用户选择
    if (binFiles.size() > 1) {
        BUGLOG("请选择要使用的固件文件 (1-%zu): ", binFiles.size());
        int choice;
        if (scanf("%d", &choice) != 1) {
            BUGLOG("输入无效 ");
            clearInputBuffer();
            return false;
        }
        clearInputBuffer();
        
        if (choice < 1 || choice > static_cast<int>(binFiles.size())) {
            BUGLOG("无效选择 ");
            return false;
        }
        
        selectedFile = binFiles[choice - 1];
    } else {
        // 如果只有一个文件，直接使用
        selectedFile = binFiles[0];
        BUGLOG("自动选择固件文件: %s ", selectedFile.c_str());
    }
    
    return true;
}

// 清空输入缓冲区
void clearInputBuffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}